package java_thinking.unit_21._21_2;

/**
 * @Desc:   2-7 重入
 * 线程可以进入任何一个它已经拥有的锁所同步着的代码块。
 * @author: cww
 * @DateTime: 2019-05-29 23:58
 */

public class Widget {
    public void doSomething(String name) throws InterruptedException {
        synchronized (this) {
            System.out.println(toString() + ": Father synchronized");
            System.out.println(name + ": Father synchronized");
            Thread.sleep(5000);
            System.out.println(name + ": wake");
        }
    }
}

/**
 * 子类改写了父类的 synchronized 方法，然后又调用父类中的方法，如果此时没有可重入的
 * 锁，那么这段代码将产生死锁，由于两个类中的 doSomething() 都是 synchronized 方法
 * ，因此每个doSomething 方法在执行前都会获取Widget上的锁，如果内置锁不是可重入的，
 * 那么在调用super.doSomething 是将无法获得Widget 上的锁
 *
 * 这里 doSomething 和 doElse 一个上锁一个不上锁，上锁的调用前就拿到了自己和父类
 * 的锁，但是两个是同一个锁，通过打印this就知道了，
 * 只要上锁的 doElse 拿到了锁，不上锁的 doSomething 就只能先执行自己内部的代码，要等
 * doElse 锁释放了才能进入
 * 如果是 doSomething 先拿到锁，doElse 的子类方法和父类方法都等待，
 * 这说明子类继承了父类，用的是同一个锁
 *
 */
class LoggingWidget extends Widget {
    @Override
    public void doSomething(String name) throws InterruptedException {
        System.out.println(toString() + ": son calling doSomething");
//        System.out.println(this);
        super.doSomething("doSomething");
    }
    public synchronized void doElse() throws InterruptedException {
        System.out.println(toString() + ": son calling doElse");
//        Thread.sleep(5000);
        super.doSomething("doElse");
    }
}

class TestExtends {
    public static void main(String[] args) throws Exception {
        final LoggingWidget l = new LoggingWidget();

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    l.doElse();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    l.doSomething("");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

//        Thread.sleep(100);
//        l.doSomething();
    }
}